package dao

import (
	"context"
	"device-admin/internal/app/grpc/client"
	"device-admin/internal/app/grpc/protoc/system_admin"
	"device-admin/internal/dal"
	"device-admin/internal/models"
	"device-admin/internal/pkg/jieba"
	"os"
	"strings"

	"192.168.1.75/go-pkg/errorx"
	"github.com/samber/lo"
)

type MallService struct{}

type MallServiceLocationList struct {
	ID         string `json:"id" gorm:"column:id"`
	Name       string `json:"name" gorm:"column:name"`
	ProvinceID string `json:"-" gorm:"column:province_id"`
	CityID     string `json:"-" gorm:"column:city_id"`
	DistrictID string `json:"-" gorm:"column:district_id"`
	Province   string `json:"province" gorm:"-"`
	City       string `json:"city" gorm:"-"`
	District   string `json:"district" gorm:"-"`
}

// Close 关闭商场服务
func (m MallService) Close(ctx context.Context, query *dal.Query, locationID string) error {
	ms := query.MallService
	res, _ := ms.WithContext(ctx).Where(ms.LocationID.Eq(locationID)).Delete(&models.MallService{})
	if res.RowsAffected <= 0 {
		return errorx.New("商场服务关闭失败", -1)
	}
	return nil
}

// OpenStatus 开通状态
// 1 表示已开通 2.表示未开通
func (m MallService) OpenStatus(ctx context.Context, query *dal.Query, locationID string) int {
	ms := query.MallService
	count, _ := ms.WithContext(ctx).Where(ms.LocationID.Eq(locationID)).Count()
	if count > 0 {
		return 1
	}
	return 2
}

// LocationList 已开通商场服务的商场
func (m MallService) LocationList(ctx context.Context, query *dal.Query, locationName string, page, limit int) ([]MallServiceLocationList, int64) {
	var records = []MallServiceLocationList{}
	l := query.Location
	ms := query.MallService
	tx := l.WithContext(ctx).Join(ms, ms.LocationID.EqCol(l.ID)).Group(l.ID)
	if locationName != "" {
		tx = tx.Where(l.Name.Like("%" + locationName + "%"))
	}
	// 获取总条数
	count, _ := tx.Count()
	// 获取分页记录
	tx.Select(l.ID, l.Name, l.ProvinceID, l.CityID, l.DistrictID).
		Order(l.ID).
		Offset(GetPageOffset(page, limit)).
		Limit(GetPageLimit(limit)).
		Scan(&records)
	if len(records) == 0 {
		records = []MallServiceLocationList{}
	}
	return records, count
}

// List 商场服务列表
func (m MallService) List(ctx context.Context, query *dal.Query, locationID string, seviceType int, status int) []*models.MallService {
	ms := query.MallService
	tx := ms.WithContext(ctx)
	if seviceType > 0 {
		tx = tx.Where(ms.Type.Eq(seviceType))
	}
	if status > 0 {
		tx = tx.Where(ms.Status.Eq(status))
	}
	records, _ := tx.Where(ms.LocationID.Eq(locationID)).
		Order(ms.Order, ms.FirstLetter).
		Find()
	if records == nil {
		records = []*models.MallService{}
	}
	return records
}

type MallServiceDetailT struct {
	models.MallService
	Questions []struct {
		ID       string `json:"id"`
		Question string `json:"question"`
		Answer   string `json:"answer"`
	} `json:"questions" gorm:"-"`
}

// Detail 服务详情
func (m MallService) Detail(ctx context.Context, query *dal.Query, serviceID string) (*models.MallService, error) {
	ms := query.MallService
	return ms.WithContext(ctx).Where(ms.ID.Eq(serviceID)).Take()
}

// Add 新增服务项
func (m MallService) Add(ctx context.Context, query *dal.Query, records []*models.MallService) error {
	ms := query.MallService
	// 确认上传的文件
	for index, record := range records {
		if !strings.Contains("/be-file/", record.Logo) {
			cli, err := client.GetSystemAdminClient()
			if err != nil {
				return errorx.New("文件确认失败", -1)
			}
			rsp, err := cli.ConfirmFile(ctx, &system_admin.ConfirmFileReq{
				FileUrl: record.Logo,
			})
			if err == nil && rsp != nil && rsp.FileUrl != "" {
				records[index].Logo = rsp.FileUrl
			}
		}
	}
	err := ms.WithContext(ctx).Create(records...)
	return err
}

// Update 更新服务项
func (m MallService) Update(ctx context.Context, query *dal.Query, record *models.MallService) error {
	// 判断服务项是否存在
	existRecord, _ := m.Detail(ctx, query, record.ID)
	if existRecord == nil {
		return errorx.New("记录不存在", -1)
	}
	// 删除不用的log
	{
		if record.Logo != "" && existRecord.Logo != record.Logo {
			os.Remove(existRecord.Logo)
		}
	}
	// 确认上传的文件
	{
		if !strings.HasPrefix("/be-file", record.Logo) {
			cli, err := client.GetSystemAdminClient()
			if err != nil {
				return errorx.New("文件确认失败", -1)
			}
			rsp, err := cli.ConfirmFile(ctx, &system_admin.ConfirmFileReq{
				FileUrl: record.Logo,
			})
			if err == nil && rsp != nil {
				record.Logo = rsp.FileUrl
			}
		}
	}
	// 更新服务
	ms := query.MallService
	res, _ := ms.WithContext(ctx).Where(ms.ID.Eq(record.ID)).Updates(record)
	if res.RowsAffected <= 0 {
		return errorx.New("更新失败", -1)
	}
	return nil
}

// Delete 删除服务项
func (m MallService) Delete(ctx context.Context, query *dal.Query, serviceID string) error {
	// 判断服务是否存在
	existRecord, _ := m.Detail(ctx, query, serviceID)
	if existRecord == nil {
		return errorx.New("记录不存在", -1)
	}
	// 删除记录
	ms := query.MallService
	res, _ := ms.WithContext(ctx).Where(ms.ID.Eq(serviceID)).Delete(&models.MallService{})
	if res.RowsAffected <= 0 {
		return errorx.New("删除失败", -1)
	}
	// 删除不用的logo
	{
		if existRecord.Logo != "" {
			os.Remove(existRecord.Logo)
		}
	}
	return nil
}

// Exists 判断服务是否存在
func (m MallService) Exists(ctx context.Context, query *dal.Query, serviceID string) bool {
	if serviceID == "" {
		return false
	}
	// 判断服务项是否存在
	existRecord, _ := m.Detail(ctx, query, serviceID)
	return !(existRecord == nil)
}

type MallServiceQA struct{}

// Add 新增商场服务问题
func (MallServiceQA) Add(
	ctx context.Context,
	query *dal.Query,
	serviceID string,
	question string,
	answer string,
) (string, error) {
	qa := query.MallServiceQA
	record := models.MallServiceQA{
		ServiceID: serviceID,
		Question:  question,
		Answer:    answer,
	}
	err := qa.WithContext(ctx).Create(&record)
	return record.ID, err
}

// List 商场服务问题列表
func (MallServiceQA) List(
	ctx context.Context,
	query *dal.Query,
	serviceID string,
) (records []*models.MallServiceQA, err error) {
	qa := query.MallServiceQA
	return qa.WithContext(ctx).Where(qa.ServiceID.Eq(serviceID)).Find()
}

// Search 商场问题查询
// 如果关键词有结果，则关键词热度加一
func (MallServiceQA) Search(
	ctx context.Context,
	query *dal.Query,
	locatioinID string,
	keyword string,
	page, limit int,
) (records []*models.MallServiceQA, total int64, err error) {
	keywords := jieba.Jieba.Cut(keyword, true)
	keywords = lo.Uniq(keywords)
	k := query.MallServiceQAKeywords
	qa := query.MallServiceQA
	// 增加热度
	k.WithContext(ctx).
		Where(k.LocationID.Eq(locatioinID)).
		Where(k.Keyword.In(keywords...)).
		Update(k.UseCount, k.UseCount.Add(1))
	// 问题列表
	tx := qa.WithContext(ctx).
		Join(k, qa.ID.EqCol(k.QuestionID)).
		Where(k.LocationID.Eq(locatioinID)).
		Where(k.Keyword.In(keywords...)).
		Select(qa.ID, qa.Question, qa.Answer).
		Order(k.ID.Desc()).
		Group(k.QuestionID)
	total, _ = tx.Count()
	records, _ = tx.Offset(GetPageOffset(page, limit)).
		Limit(GetPageLimit(limit)).
		Order(qa.ID.Desc()).
		Find()
	if len(records) <= 0 {
		records = []*models.MallServiceQA{}
	}
	return
}

// Detail 问答详情
func (MallServiceQA) Detail(
	ctx context.Context,
	query *dal.Query,
	questionID string,
) (*models.MallServiceQA, error) {
	qa := query.MallServiceQA
	return qa.WithContext(ctx).Where(qa.ID.Eq(questionID)).Take()
}

// Exists 判断问题id是否存在
func (MallServiceQA) Exists(
	ctx context.Context,
	query *dal.Query,
	questionID string,
) bool {
	qa := query.MallServiceQA
	count, _ := qa.WithContext(ctx).Where(qa.ID.Eq(questionID)).Count()
	return count > 0
}

// Update 更新问答
func (MallServiceQA) Update(
	ctx context.Context,
	query *dal.Query,
	questionID string,
	question string,
	answer string,
) error {
	qa := query.MallServiceQA
	// 获取详情
	detail, _ := MallServiceQA{}.Detail(ctx, query, questionID)
	if detail == nil {
		return errorx.New("问答不存在", -1)
	}
	// 如果问题有更新，则同步更新关键字
	if detail.Question != question {
		MallServiceQAKeywords{}.Delete(ctx, query, questionID)
		MallServiceQAKeywords{}.Add(ctx, query, questionID, question)
	}
	// 更新新的问题/答案
	res, _ := qa.WithContext(ctx).
		Where(qa.ID.Eq(questionID)).
		Updates(&models.MallServiceQA{
			Question: question,
			Answer:   answer,
		})
	if res.RowsAffected <= 0 {
		return errorx.New("更新失败", -1)
	}
	return nil
}

// Delete 删除问答
func (MallServiceQA) Delete(
	ctx context.Context,
	query *dal.Query,
	questionID string,
) error {
	qa := query.MallServiceQA
	_, err := qa.WithContext(ctx).Where(qa.ID.Eq(questionID)).Delete(&models.MallServiceQA{})
	if err != nil {
		return errorx.New("删除失败", -1)
	}
	k := query.MallServiceQAKeywords
	_, err = k.WithContext(ctx).Where(k.QuestionID.Eq(questionID)).Delete(&models.MallServiceQAKeywords{})
	return err
}

// MallServiceQAKeywords 商场服务问答关键字
type MallServiceQAKeywords struct{}

func (MallServiceQAKeywords) Add(
	ctx context.Context,
	query *dal.Query,
	questionID string,
	question string,
) error {
	// 判断问答是否存在
	questionDetail, _ := MallServiceQA{}.Detail(ctx, query, questionID)
	if questionDetail == nil {
		return errorx.New("问答不存在", -1)
	}
	// 查看服务详情
	serviceDetail, _ := MallService{}.Detail(ctx, query, questionDetail.ServiceID)
	if serviceDetail == nil {
		return errorx.New("问答不存在", -1)
	}
	// 问题分词
	keywords := jieba.Jieba.Cut(question, true)
	keywords = lo.Uniq(keywords)
	// 新增
	k := query.MallServiceQAKeywords
	records := []*models.MallServiceQAKeywords{}
	for _, keyword := range keywords {
		records = append(records, &models.MallServiceQAKeywords{
			LocationID: serviceDetail.LocationID,
			QuestionID: questionID,
			Keyword:    keyword,
		})
	}
	return k.WithContext(ctx).CreateInBatches(records, 300)
}

// Delete 删除关键字
func (MallServiceQAKeywords) Delete(
	ctx context.Context,
	query *dal.Query,
	questionID string,
) error {
	k := query.MallServiceQAKeywords
	_, err := k.WithContext(ctx).Where(k.QuestionID.Eq(questionID)).Delete(&models.MallServiceQAKeywords{})
	return err
}

// hostKeywords 获取热词
func (MallServiceQAKeywords) HotKeywords(
	ctx context.Context,
	query *dal.Query,
	locationID string,
) (keywords []string, err error) {
	k := query.MallServiceQAKeywords
	list, _ := k.WithContext(ctx).
		Distinct(k.Keyword).
		Where(k.LocationID.Eq(locationID)).
		Where(k.UseCount.Gt(0)).
		Order(k.UseCount.Desc(), k.UpdatedAt.Desc()).
		Limit(8).
		Find()
	for _, record := range list {
		keywords = append(keywords, record.Keyword)
	}
	return keywords, nil
}
